/**
 * @author jjophin
 */
var ibanValidator = (function(){
    var regObj = {
        trim: "[^a-zA-Z\\d]",
        countryCode: "^([A-Z]{2})",
        controlDigits: "([0-9]{2})",
        n: "[0-9]",
        c: "[A-Za-z0-9]",
        a: "[A-Z]"
    };
    var alphaList = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    var _trimIBAN = function(iban){
        return iban.replace(RegExp(regObj.trim, "g"), ""); //stripping all the whitespaces and special characters
    };
    
    var _calcIBANModulus = function(iban){
        var ibanArr = iban.replace(RegExp(regObj.countryCode + regObj.controlDigits + "(.*)$"), "$3$1$2");
        ibanArr.replace(RegExp('(' + regObj.a + ')', 'g'), function(match){
            ibanArr = ibanArr.replace(match, alphaList.indexOf(match) + 10);
        });
        ibanArr = ibanArr.split("").reverse();
        var prevAi = 0.1, sum = 0;
        for (var i = 0; i < ibanArr.length; i++) {
            prevAi = (prevAi * 10) % 97;
            sum += (ibanArr[i] * prevAi);
        }
        return sum % 97;
    }
    
    var getCountryCode = function(iban){
        iban = _trimIBAN(iban);
        if (iban.search(RegExp(regObj.countryCode)) == -1) 
            return {
                isValid: false,
                errorString: "Invalid country code. The first 2 characters in the IBAN should be upper case alphabets representing the country code."
            };
        if (iban.search(RegExp(regObj.countryCode + regObj.controlDigits)) == -1) 
            return {
                isValid: false,
                errorString: "Invalid control digits. The 3rd and 4th characters in the IBAN should be digits."
            };
        return {
            isValid: true,
            value: RegExp.$1
        }
    };
    
    var isValidIBAN = function(iban, country, charCount, bban){
        iban = _trimIBAN(iban);
        if (country == "") 
            return {
                isValid: false,
                errorString: "No country has been found with the country code provided in the IBAN number."
            };
        if (iban.length != charCount) 
            return {
                isValid: false,
                errorString: "The IBAN provided does not conform with the required IBAN length for " + country
            };
        
        var bbanArr = bban.split(',');
        var regStr = regObj.countryCode + regObj.controlDigits;
        for (var i = 0; i < bbanArr.length; i++) 
            regStr += "(" + regObj[bbanArr[i].charAt(bbanArr[i].length - 1)] + "{" + parseInt(bbanArr[i]) + "})";
        regStr += "$";
        if (iban.search(RegExp(regStr)) == -1) 
            return {
                isValid: false,
                errorString: "The IBAN provided does not conform with the BBAN format for " + country
            };
        if (_calcIBANModulus(iban) != 1) 
            return {
                isValid: false,
                errorString: "The number provided is not a valid IBAN"
            };
        return {
            isValid: true
        };
    };
    
    return {
        getCountryCode: getCountryCode,
        isValidIBAN: isValidIBAN
    };
})();
